package edu.hawaii.duedates.lender;

import java.io.IOException;
import java.util.List;
import java.util.ArrayList;
import org.xml.sax.SAXException;

import com.meterware.httpunit.HttpUnitOptions;
import com.meterware.httpunit.WebForm;
import com.meterware.httpunit.WebLink;
import com.meterware.httpunit.WebResponse;
import com.meterware.httpunit.WebTable;


/**
 * Hawaii State Public Library class. Contains all the necessary methods to log
 * in and retrieve the borrowed items from the library system.
 * 
 * @author Daniel Tian
 * @author Aric West
 */
public class HawaiiStatePublicLibrary extends Lender {
  /**
   * Constructor. Assigns the number of fields this class expects, the full
   * library name, and instantiates the ArrayList object used to store the list
   * of borrowed items.
   */
  public HawaiiStatePublicLibrary() {
    this.lenderName = "Hawaii State Public Library System";
    this.url = "http://www.librarieshawaii.org/";
    this.logonFormName = "security";
    this.field1Name = "sec1";
    this.field2Name = "sec2";
    this.loginFailedText = "Login failed.";
  }

  /**
   * Logs into the Hawaii State Public Library system using a library id and a
   * PIN. This code is modified from Philip Johnson's bootstrap code available
   * here:
   * 
   * http://groups.google.com/group/ics-software-engineering-fall-2008/
   * web/DueDateBootstrap-1.0.1010.zip
   * 
   * @throws LogInException If the login was unsuccessful.
   */
  public void logIn() throws LogInException {
    try {
      if (this.field1Value == null || this.field2Value == null) {
        throw new LogInException("ID number and last name were not provided");
      }
      else {
        // Disable exceptions thrown on Javascript errors, this is required for this library
        HttpUnitOptions.setExceptionsThrownOnScriptError(false);
        
        WebResponse response = this.conversation.getResponse(this.url);
        WebLink link = response.getLinkWith("My Account");
        link.click();
        response = conversation.getCurrentPage();
        
        WebForm form = response.getFormWithName(this.logonFormName);
        form.setParameter(this.field1Name, this.field1Value);
        form.setParameter(this.field2Name, this.field2Value);
        form.submit();
        
        response = this.conversation.getCurrentPage();
        
        if (response.getText().contains(loginFailedText)) {
          throw new LogInException("wrong user name or password");
        }
      }
    }
    catch (IOException e) {
      throw new LogInException("could not open login web page", e);
    }
    catch (SAXException e) {
      throw new LogInException("an error occurred while parsing the login web page", e);
    }
    catch (NullPointerException e) {
      throw new LogInException("null pointer encountered, page URL or layout may have changed", e);
    }
  }
  
  /**
   * Acquires and generates the list of borrowed items and their due dates.
   * 
   * @throws ParseItemException If the parsing failed.
   * @throws LogInException If an error occurred that prevented login.
   */
  public void queryBorrowedItems() throws ParseItemException, LogInException {
    if (!this.loggedOn) {
      this.logIn();
    }
    
    try {
      WebResponse response = this.conversation.getCurrentPage();
      WebLink link = response.getLinkWith("Items Out");
      link.click();
      response = this.conversation.getCurrentPage();
      
      if (!response.getText().contains("Checked Out: 0")) {
        WebTable table = response.getTableStartingWith("Title");
        List<String> fieldList = new ArrayList<String>();
        
        String itemName = null;
        String dueDate = null;
        
        for (int i = 1; i < table.getRowCount(); i++) {
          itemName = table.getCellAsText(i, 0).replaceAll("\n", "");
          dueDate = table.getCellAsText(i, 2);
        }
        
        try {
          BorrowedItem item = new BorrowedItem(itemName, dueDate);
          this.itemList.add(item);
        }
        catch (BorrowedItemException e) {
          throw new ParseItemException("Could not parse " + this.itemList.get(1) + ":" +
              e.getMessage(), e);
        }
        
        fieldList.clear();
      }
    }
    catch (IOException e) {
      throw new ParseItemException("could not open 'items out' web page", e);
    } 
    catch (SAXException e) {
      throw new ParseItemException("an error occurred while parsing the 'items out' web page", e);
    }
    catch (NullPointerException e) {
      throw new ParseItemException(
        "null pointer encountered, page URL or layout may have changed", e);
    }
  }
  
  /**
   * Checks that a compared object is this type they have the same name and item list.
   * Also should later check for equality of id and last name.
   * 
   * @param o object
   * @return boolean value
   */
  public boolean equals(Object o) {
    if (o == this) {
      return true;
    }
    if (!(o instanceof HawaiiStatePublicLibrary)) {
      return false;
    }
    
    HawaiiStatePublicLibrary query = (HawaiiStatePublicLibrary)o;
    return query.lenderName.equals(this.lenderName) && query.itemList.equals(this.itemList);
  }

  /**
   * Calculates a hashcode for this object based on size of book list and expected parameters size.
   * Should use the id number later.
   * 
   * @return A hash value based on the due date of the item.
   */
  public int hashCode() {
    int hash = 7;
    hash = 31 * hash + this.lenderName.length();
    hash = 31 * hash + this.itemList.toString().length();
    
    return hash;
  }
}
